#pragma once
#include "net.hpp"
#include "message.hpp"

namespace rcrpc {
    class Callback {
        public:
            using ptr = std::shared_ptr<Callback>;
            virtual void onMessage(const BaseConnection::ptr& conn, BaseMessage::ptr& msg) = 0;
    };

    template<typename T>
    class CallbackT :public Callback{
        public:
            using ptr = std::shared_ptr<CallbackT<T>>;
            using MessageCallback = std::function<void(const BaseConnection::ptr&,std::shared_ptr<T> &msg)>;
            CallbackT(const MessageCallback &handler):_handler(handler){}
            virtual void onMessage(const BaseConnection::ptr& conn, BaseMessage::ptr& msg) override{
                // rpc请求，向下类型转化，来调用处理rpc请求
                //如果T是响应类型时(即BaseMessage),传入requestor, 则下面的类型转化传回原指针,获取响应即可
                auto type_msg = std::dynamic_pointer_cast<T>(msg);
                _handler(conn,type_msg);
            };
        private:
            MessageCallback _handler;
    };
    class Dispatcher {
        public:
            using ptr = std::shared_ptr<Dispatcher>;
            template<typename T>
            void registerHandler(MType mtype,const typename CallbackT<T>::MessageCallback &handler){
                std::lock_guard<std::mutex> lock(_mutex);
                auto cb = std::make_shared<CallbackT<T>>(handler); //外部传回一个回调函数，进行保存
                if (_handles.find(mtype)!=_handles.end()){
                    ELOG("重复注册消息类型：%d",mtype);
                    return;
                }
                _handles.insert(std::make_pair(mtype, cb)); // 后面用基类指针保存派生类指针
            }
            void onMessage(const BaseConnection::ptr& conn, BaseMessage::ptr& msg){
                // 找到消息类型对应的业务处理函数，进行调用即可
                std::lock_guard<std::mutex> lock(_mutex);
                auto it = _handles.find(msg->mtype());
                if (it != _handles.end()){
                    // 调用回调函数
                    return it->second->onMessage(conn,msg);
                }
                // 没有找到指定类型的处理回调--因为客户端和服务端是我们自己设计的，因此不可能出现这种情况
                ELOG("收到未知类型的消息：%d",msg->mtype());
                conn->shutdown();
            }
        private:
            std::mutex _mutex;
            std::unordered_map<MType, Callback::ptr> _handles;
    };
}